package com.free.semantic.web.controller;

import com.free.semantic.common.ParamNode;
import com.free.semantic.common.RangeObj;
import com.free.semantic.common.RelationChain;
import com.free.semantic.common.RelationItem;
import com.free.semantic.core.ConceptInstanceManage;
import com.free.semantic.core.ConceptManage;
import com.free.semantic.core.script.impl.ScriptEngineImpl;
import com.free.semantic.core.service.FreeService;
import com.free.semantic.core.takeclient.impl.UrlClientImpl;
import com.free.semantic.facade.Link;
import com.free.semantic.facade.Node;
import com.free.semantic.web.configure.ControllerConfig;
import com.free.semantic.web.entity.QueryPath;
import com.free.semantic.web.req.*;
import com.free.semantic.web.result.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;


@CrossOrigin(methods = {RequestMethod.GET, RequestMethod.POST, RequestMethod.OPTIONS})
@RestController
@ControllerConfig
@RequestMapping("/general_controller")
public class GeneralController {

    @Value("${baseUrl}")
    private String baseUrl;

    @Resource
    private FreeService freeService;

    private static final String HABIT_MODEL = "habitModel";

    // node1-value,node2-value;dest
    @GetMapping(value = "concept/{conceptName}/{script}")
    public Result<Object> conceptParseScript(@PathVariable("conceptName") String conceptName,
                                             @PathVariable("script") String script) {
        if (StringUtils.isBlank(script) || StringUtils.isBlank(conceptName)) {
            throw new IllegalArgumentException();
        }
        Object result = freeService.execScript(conceptName, script);
        return Result.success(result);
    }

    // node1-value,node2-value;dest
    @Deprecated
    @GetMapping(value = "parseScript/{script}")
    public Result<Object> parseScript(@PathVariable("script") String script) {
        if (StringUtils.isBlank(script)) {
            throw new IllegalArgumentException();
        }
        Object result = freeService.execScript(HABIT_MODEL, script);
        return Result.success(result);
    }

    // node1-value,node2-value;dest
    @PostMapping(value = "parse")
    public Result<Object> parse(@RequestBody ParseRequest parseRequest) {
        if (StringUtils.isBlank(parseRequest.getScript()) || StringUtils.isBlank(parseRequest.getConceptName())) {
            throw new IllegalArgumentException();
        }
        Object result = freeService.build(parseRequest.getConceptName(), parseRequest.getScript());
        return Result.success(result);
    }

    @PostMapping(value = "createInterfaceModel")
    public Result<CreateInterfaceModelResult> createInterfaceModel(@RequestBody CreateInterfaceModelReq modelReq) {
        ConceptInstanceManage manage = freeService.get(modelReq.getImplementConcept());
        if (manage == null) {
            throw new RuntimeException(String.format("不存在%s的概念网络", modelReq.getImplementConcept()));
        }
        String targetConceptName = modelReq.getTargetConceptName();
        UrlClientImpl localMange = null;
        localMange = new UrlClientImpl(baseUrl + modelReq.getTargetInterfaceUrl());
        com.free.semantic.core.script.SemanticNetEngine engine = new ScriptEngineImpl();
        ConceptManage conceptManage = engine.buildManageFromTake(localMange);
        ConceptInstanceManage instanceManage = engine.execScript(conceptManage, modelReq.getScript(), manage);
        freeService.set(targetConceptName, instanceManage);

        Map<String, String> formulaMap = ScriptEngineImpl.parseFormulaMap(modelReq.getScript());
        String currentPosition = modelReq.getCurrentPosition();
        ParamNode parse = ParamNode.parse(currentPosition);
        if (formulaMap.containsKey(parse.getNodeName())) {
            parse.setNodeName(formulaMap.get(parse.getNodeName()));
        }
        CreateInterfaceModelResult result = new CreateInterfaceModelResult();
        result.setUrl(String.format("%s%s/take %s", baseUrl + "/manage/general_controller/concept/", targetConceptName, parse));
        return Result.success(result);
    }

    /**
     * 我在进入语义网络之前，我在哪里？、
     * <p>
     * 1. 完成用户登录 2.
     *
     * @return
     */
    @PostMapping("getValue")
    public Result<List<Object>> getValue(@RequestBody TaskPathRequest taskPathRequest) {
        if (StringUtils.isBlank(taskPathRequest.getConceptName())) {
            taskPathRequest.setConceptName(HABIT_MODEL);
        }
        List<Object> value = freeService.takePath(taskPathRequest.getConceptName(), taskPathRequest.getFrom(),
                taskPathRequest.getDestObject());
        return Result.success(value);
    }

    // node1-value,node2-value;dest
    @GetMapping(value = {"takePath/{conceptName}/{node}/{dest}", "takePath/{node}/{dest}"})
    public Result<List<Object>> takePath(@PathVariable(name = "conceptName", required = false) String conceptName,
                                         @PathVariable("node") String nodeValueStr,
                                         @PathVariable("dest") String dest) {
        if (StringUtils.isBlank(nodeValueStr) || StringUtils.isBlank(dest)) {
            throw new IllegalArgumentException();
        }
        if (StringUtils.isBlank(conceptName)) {
            conceptName = HABIT_MODEL;
        }
        List<Object> value = freeService.takePath(conceptName, parse(nodeValueStr), dest);
        return Result.success(value);
    }

    @PostMapping("searchPath")
    public Result<List<QueryPath>> searchPath(@RequestBody SearchPathReq searchPathReq) {
        if (searchPathReq == null || searchPathReq.getDestObject() == null || searchPathReq.getFrom() == null
                || searchPathReq.getFrom().size() == 0) {
            return Result.success(new ArrayList<>());
        }
        if (StringUtils.isBlank(searchPathReq.getConceptName())) {
            searchPathReq.setConceptName(HABIT_MODEL);
        }
        List<RelationChain> relationChains =
                freeService.searchPath(HABIT_MODEL, searchPathReq.getFrom(), searchPathReq.getDestObject());
        return Result.success(relationChains.stream().map(this::convert).collect(Collectors.toList()));
    }

    @GetMapping(value = {"getAllNode/{conceptName}", "getAllNode"})
    public Result<List<Node>> getAllNode(@PathVariable(name = "conceptName", required = false) String conceptName) {
        if (StringUtils.isBlank(conceptName)) {
            conceptName = HABIT_MODEL;
        }
        return Result.success(freeService.getAllNode(conceptName));
    }

    @GetMapping(value = {"getAllLink/{conceptName}", "getAllLink"})
    public Result<List<Link>> getAllLink(@PathVariable(name = "conceptName", required = false) String conceptName) {
        if (StringUtils.isBlank(conceptName)) {
            conceptName = HABIT_MODEL;
        }
        return Result.success(freeService.getAllLink(conceptName));
    }

    private String getSimpleName(String objectName) {
        String[] split = objectName.split(":");
        return split[split.length - 1];
    }

    private QueryPath convert(RelationChain relationChain) {

        QueryPath queryPath = new QueryPath();
        Set<String> nodeId = new HashSet<>();
        List<Link> links = new ArrayList<>();
        List<Node> nodes = new ArrayList<>();

        List<Node> request = new ArrayList<>();

        List<Node> allRequest = new ArrayList<>();

        List<RangeObj> rangeObjs = relationChain.getSourceObjectList();

        for (RangeObj rangeObj : rangeObjs) {
            Node node = new Node();
            node.setName(getSimpleName(rangeObj.getObjectName()));
            node.setId(rangeObj.getObjectName());
            allRequest.add(node);

            if (!rangeObj.getObjectName().startsWith("@")) {
                request.add(node);
            }
        }

        queryPath.setRequestParam(request);
        queryPath.setAllRequestParam(allRequest);

        RangeObj dest = relationChain.getDestObject();

        if (nodeId.add(dest.getObjectName())) {
            Node node = new Node();
            node.setName(getSimpleName(dest.getObjectName()));
            node.setId(dest.getObjectName());
            nodes.add(node);
            queryPath.setDestObj(node);
        }

        for (RelationItem relationItem : relationChain.getRelationItems()) {
            List<RangeObj> sourceObjectList = relationItem.getSourceObjectList();
            RangeObj destObject = relationItem.getDestObject();

            if (nodeId.add(destObject.getObjectName())) {
                Node node = new Node();
                node.setName(getSimpleName(destObject.getObjectName()));
                node.setId(destObject.getObjectName());
                nodes.add(node);
            }
            for (RangeObj rangeObj : sourceObjectList) {
                if (rangeObj.getObjectName().startsWith("@")) {
                    continue;
                }
                String objectName = rangeObj.getObjectName();
                if (nodeId.add(objectName)) {
                    Node node = new Node();
                    node.setName(getSimpleName(objectName));
                    node.setId(objectName);
                    nodes.add(node);
                }
                Link link = new Link();
                link.setFrom(rangeObj.getObjectName());
                link.setTo(destObject.getObjectName());
                links.add(link);
            }
        }
        queryPath.setLinks(links);
        queryPath.setNodes(nodes);
        return queryPath;
    }

    private List<ParamNode> parse(String nodeValueStr) {
        List<ParamNode> res = new ArrayList<>();
        String[] split = nodeValueStr.split(",");
        for (String express : split) {

            String[] nodeAndValue = express.split("-");
            ParamNode info = new ParamNode();
            info.setNodeName(nodeAndValue[0]);
            if (nodeAndValue.length > 1) {
                info.setValue(nodeAndValue[1]);
            }
            res.add(info);
        }
        return res;
    }

}
